package test01.demo08.demo0803;

import test01.demo02.userOperation.tools.Const;
import test01.demo03.ConnectionTool;

import java.lang.reflect.Field;
import java.sql.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class ObjectOperation {

    public static void insertObject(Object object){
        Connection conn = null;
        PreparedStatement ps = null;
        //创建需要添加到表中的属性的索引列表
        List<Integer> toAddFieldIndexList = new ArrayList<>();

        String tableName = "";
        String fieldName = "";

        //获取对象的Class类型
        Class objClass = object.getClass();

        //判断当前类对象对应的类中是否存在Table这个注解
        if (objClass.isAnnotationPresent(Table.class)){
            //如果有，则就把这个注解的value值作为表名
            Table table = (Table) objClass.getDeclaredAnnotation(Table.class);
            tableName = table.value();
        }else{
            //获取当前对象的类名直接作为sql语句的表名
            tableName = objClass.getSimpleName().toLowerCase();
        }

        try {
            Class.forName(Const.DRIVER);
            conn = DriverManager.getConnection(Const.URL_TEST,Const.USERNAME,Const.PASSWORD);

            StringBuffer sb = new StringBuffer("insert into "+tableName+"(");

            //获取当前对象的类中所有属性数组
            Field[] fields = objClass.getDeclaredFields();

            //遍历所有的属性
            for (int i = 0; i < fields.length; i++) {
                Field currentField = fields[i];

                //需要先判断主键里的那个字段是否为自增长
                if (currentField.isAnnotationPresent(PrimaryKey.class)){
                    PrimaryKey primaryKeyAnnotation = currentField.getDeclaredAnnotation(PrimaryKey.class);
                    if (primaryKeyAnnotation.autoIncrement()){
                        //如果是的话就跳出当前循环，执行下一个循环
                        continue;
                    }
                }

                //无论是否为主键都是需要添加的列
                toAddFieldIndexList.add(i);

                //再判断是否有Column注解，如果有的话就要读取Column注解中的value值作为要添加的字段
                if (currentField.isAnnotationPresent(Column.class)){
                    Column columnAnnotation = currentField.getDeclaredAnnotation(Column.class);
                    fieldName = columnAnnotation.value();
                }else {
                    //如果没有就直接读取属性名作为要添加的字段名
                    fieldName = currentField.getName().toLowerCase();
                }

                sb.append(fieldName + (i==fields.length-1?")":","));
            }
            sb.append(" values(");

            //接下来处理的是要添加的属性，应该有多少个问号，这里可以用list存储该属性在属性列表里的索引值
            for (int i = 1; i <= toAddFieldIndexList.size(); i++) {
                sb.append(i==toAddFieldIndexList.size()?"?)":"?,");
            }

            //对sql语句进行预处理
            ps = conn.prepareStatement(sb.toString());

            //设置sql语句里的问号值
            for (int i = 0; i < toAddFieldIndexList.size(); i++) {
                //获取属性数组中索引值为toAddFieldIndexList中的第i个索引值
                Field currentField = fields[toAddFieldIndexList.get(i)];
                currentField.setAccessible(true);
                //从对象中获取相应的属性值
                Object fieldValue = currentField.get(object);
                ps.setObject(i+1,fieldValue);
            }

            int result = ps.executeUpdate();
            if(result==1){
                System.out.println("添加成功");
            }else {
                System.out.println("添加失败");
            }

        } catch (Exception e) {
            throw new RuntimeException(e);
        }finally {
            ConnectionTool.closed(conn,ps);
        }

    }

    public static void update(Object object){
        Connection conn = null;
        PreparedStatement ps = null;
        //创建需要添加到表中的属性的索引列表
        List<Integer> toAddFieldIndexList = new ArrayList<>();
        String tableName = "";
        String fieldName = "";
        Object primaryKey = null;
        //获取对象的Class类型
        Class objClass = object.getClass();

        //判断当前类对象对应的类中是否存在Table这个注解
        if (objClass.isAnnotationPresent(Table.class)){
            //如果有，则就把这个注解的value值作为表名
            Table table = (Table) objClass.getDeclaredAnnotation(Table.class);
            tableName = table.value();
        }else{
            //获取当前对象的类名直接作为sql语句的表名
            tableName = objClass.getSimpleName().toLowerCase();
        }

        try {
            Class.forName(Const.DRIVER);
            conn = DriverManager.getConnection(Const.URL_TEST,Const.USERNAME,Const.PASSWORD);

            //update 表名 set 属性名 = ？, 属性名 = ？， ，，，（修改除主键外的值） where 主键 = ?;
            //insert into from 表名(,,,) values (???)
            StringBuffer sb = new StringBuffer("update "+tableName+" set ");

            //获取当前对象的类中所有属性数组
            Field[] fields = objClass.getDeclaredFields();

            //遍历所有的属性
            for (int i = 0; i < fields.length; i++) {
                Field currentField = fields[i];

                //需要先判断该属性是否为主键
                //如果不是主键则再判断它是否有Column注解，如果有就要读取Column注解中的value值作为要添加的字段
                if (!currentField.isAnnotationPresent(PrimaryKey.class)){
                    if (currentField.isAnnotationPresent(Column.class)){
                        Column columnAnnotation = currentField.getDeclaredAnnotation(Column.class);
                        fieldName = columnAnnotation.value();
                    }else {
                        //如果没有就直接读取属性名作为要添加的字段名
                        fieldName = currentField.getName().toLowerCase();
                    }
                    sb.append(fieldName+(i==fields.length-1?"=?":"=?,"));
                    toAddFieldIndexList.add(i);
                }

            }

            //接下来再次循环所有的属性，判断该属性的注解是否为主键
            for (int i = 0; i < fields.length; i++) {
                Field currentField = fields[i];

                //需要先判断该属性是否为主键
                //如果是主键则再判断它是否有Column注解，如果有就要读取Column注解中的value值作为要添加的字段
                if (currentField.isAnnotationPresent(PrimaryKey.class)){
                    if (currentField.isAnnotationPresent(Column.class)){
                        Column columnAnnotation = currentField.getDeclaredAnnotation(Column.class);
                        primaryKey = columnAnnotation.value();
                    }else {
                        //如果没有就直接读取属性名作为要添加的字段名
                        primaryKey = currentField.getName().toLowerCase();
                    }
                    sb.append(" where " + primaryKey + "=?");
                }
                toAddFieldIndexList.add(i);
            }

            //对sql语句进行预处理
            ps = conn.prepareStatement(sb.toString());

            //设置sql语句里的问号值
            for (int i = 0; i < fields.length; i++) {
                //获取属性数组中索引值为toAddFieldIndexList中的第i个索引值
                Field currentField = fields[toAddFieldIndexList.get(i)];
                currentField.setAccessible(true);
                //从对象中获取相应的属性值
                Object fieldValue = currentField.get(object);
                ps.setObject(i+1,fieldValue);
            }

            int result = ps.executeUpdate();
            if(result==1){
                System.out.println("更新成功");
            }else {
                System.out.println("更新失败");
            }

        } catch (Exception e) {
            throw new RuntimeException(e);
        }finally {
            ConnectionTool.closed(conn,ps);
        }

    }

    /**
     * 根据类名和主键删除记录
     * @param clazz 需要删除的类型
     * @param pk 主键
     */
    public static void delete(Class clazz,Object pk){

        Connection conn = null;
        PreparedStatement ps = null;

        String tableName = "";
        String fieldName = "";
        Object primaryKey = null;

        //判断当前类中是否存在Table这个注解
        if (clazz.isAnnotationPresent(Table.class)){
            //如果有，则就把这个注解的value值作为表名
            Table table = (Table) clazz.getDeclaredAnnotation(Table.class);
            tableName = table.value();
        }else{
            //获取当前类名直接作为sql语句的表名
            tableName = clazz.getSimpleName().toLowerCase();
        }

        try {
            Class.forName(Const.DRIVER);
            conn = DriverManager.getConnection(Const.URL_TEST,Const.USERNAME,Const.PASSWORD);

            //delete from 表名 where 主键=?
            //update 表名 set 属性名 = ？, 属性名 = ？， ，，，（修改除主键外的值） where 主键 = ?;
            //insert into from 表名(,,,) values (???)
            StringBuffer sb = new StringBuffer("delete from "+tableName+" where ");

            //获取当前类中所有属性数组
            Field[] fields = clazz.getDeclaredFields();

            //循环所有的属性，判断该属性的注解是否为主键
            for (int i = 0; i < fields.length; i++) {
                Field currentField = fields[i];
                //需要先判断该属性是否为主键
                if (currentField.isAnnotationPresent(PrimaryKey.class)){
                    if (currentField.isAnnotationPresent(Column.class)){
                        Column columnAnnotation = currentField.getDeclaredAnnotation(Column.class);
                        primaryKey = columnAnnotation.value();
                    }else {
                        //如果没有就直接读取属性名作为要添加的字段名
                        primaryKey = currentField.getName().toLowerCase();
                    }
                    sb.append(primaryKey + "=?");
                    break;
                }
            }


            //对sql语句进行预处理
            ps = conn.prepareStatement(sb.toString());

            //设置sql语句里的问号值
            ps.setObject(1,pk);

            int result = ps.executeUpdate();
            if(result==1){
                System.out.println("删除成功");
            }else {
                System.out.println("删除失败");
            }

        } catch (Exception e) {
            throw new RuntimeException(e);
        }finally {
            ConnectionTool.closed(conn,ps);
        }
    }

    public static <T> List<T> getList(Class<T> clazz){
        Connection conn = null;
        PreparedStatement ps = null;

        String tableName = "";
        ResultSet rs = null;

        List<T> list = new ArrayList<>();

        //判断当前类中是否存在Table这个注解
        if (clazz.isAnnotationPresent(Table.class)){
            //如果有，则就把这个注解的value值作为表名
            Table table = (Table) clazz.getDeclaredAnnotation(Table.class);
            tableName = table.value();
        }else{
            //获取当前类名直接作为sql语句的表名
            tableName = clazz.getSimpleName().toLowerCase();
        }

        try {
            Class.forName(Const.DRIVER);
            conn = DriverManager.getConnection(Const.URL_TEST,Const.USERNAME,Const.PASSWORD);

            //select * from 表名
            //delete from 表名 where 主键=?
            //update 表名 set 属性名 = ？, 属性名 = ？， ，，，（修改除主键外的值） where 主键 = ?;
            //insert into from 表名(,,,) values (???)
            StringBuffer sb = new StringBuffer("select * from "+tableName);

            //对sql语句进行预处理
            ps = conn.prepareStatement(sb.toString());

            rs = ps.executeQuery();

            //获取结果集的元数据
            ResultSetMetaData rsmd = rs.getMetaData();
            int columnCount = rsmd.getColumnCount();

            //每执行一次while，就是一条元数据集
            while (rs.next()){
                Map<String,Object> map = new HashMap<>();
                for (int i = 1; i <= columnCount; i++) {
                    map.put(rsmd.getColumnName(i),rs.getObject(i));
                }
                list.add((T) map);
            }

        } catch (Exception e) {
            throw new RuntimeException(e);
        }finally {
            ConnectionTool.closed(conn,ps,rs);
        }
        return list;
    }


    public static void main(String[] args) {
        Teachers teacher = new Teachers(101,"tom");
        //Customer customers = new Customer("Tom",2,"hlj",100);
        Customer customers = new Customer(3,"Tom",3,"hlj",100);


        //insertObject(customers);
        //update(customers);
        //delete(Customer.class,3);
        System.out.println(getList(Customer.class));
    }
}
